16 research outputs found

    Analyzing Concurrency Bugs Using Dual Slicing

    Get PDF
    Recently, there has been much interest in developing analyzes to detect concurrency bugs that arise because of data races, atomicity violations, execution omission, etc. However, determining whether reported bugs are in fact real, and understanding how these bugs lead to incorrect behavior, remains a labor-intensive process. This paper proposes a novel dynamic analysis that automatically produces the causal path of a concurrent failure leading from the root cause to the failure. Given two schedules, one inducing the failure and the other not, our technique collects traces of the two executions, and compares them to identify salient differences. The causal relation between the differences is disclosed by leveraging a novel slicing algorithm called dual slicing that slices both executions alternatively and iteratively, producing a slice containing trace differences from both runs. Our experiments show that dual slices tend to be very small, often an order of magnitude or more smaller than the corresponding dynamic slices; more importantly, they enable precise analysis of real concurrency bugs for large programs, with reasonable overhead

    Dynamic program analyses for debugging concurrency bugs in large multi-threaded programs

    No full text
    Concurrency bugs are problems due to incorrect interleaving of parallel tasks. They are often caused by inadequate synchronization. Unlike bugs in sequential programs, manifestation of concurrency bugs is dependent not only on the program input but also on the scheduling of different tasks. Hence they are non-deterministic and consequently debugging concurrent programs is far more difficult than debugging sequential programs. In the real world, concurrency bugs have caused several disasters in the past and are generating increasingly severe problems in recent times with the prevalence of multi-core hardware. This thesis presents new dynamic techniques to debug concurrency bugs in large multithreaded programs. We make four main contributions. Our first and second contributions are two dynamic techniques that aid in reproducing concurrency bugs observed in production runs and in testing concurrent programs, respectively. Our bug reproduction technique uses information gleaned from crash coredumps to narrow down the set of schedules that needs to be explored by a bounded model checker. Our testing technique uses predicate switching to mutate correct single-threaded executions of a multi-threaded program to erroneous executions. We then use the switched predicates to identify a second conflicting input from a large regression test suite that if executed concurrently with the first input could trigger the same program failure. Once a bug has been reproduced, the next step in debugging involves identifying the root cause. Hence our third contribution is a new dynamic slicing technique that produces dynamic slices order of magnitude smaller than traditional slices by comparing correct and incorrect executions of a concurrent program. Through analysis of many concurrency bugs we observe that developers find it difficult to fix concurrency bugs successfully due to the complexity of reasoning that is required to develop a correct software patch. Hence in our forth contribution, we discuss a technique that can suppress certain latent concurrency bugs which avoids debugging altogether

    Accentuating the Positive: Atomicity Inference and Enforcement Using Correct Executions

    Get PDF
    Concurrency bugs are often due to inadequate synchronization that fail to prevent specific (undesirable) thread interleavings. Such errors, often referred to as Heisenbugs, are difficult to detect, prevent, and repair. In this paper, we present a new technique to increase program robustness against Heisenbugs. We profile correct executions from provided test suites to infer fine-grained atomicity properties. Additional deadlock-free locking is injected into the program to guarantee these properties hold on production runs. Notably, our technique does not rely on witnessing or analyzing erroneous executions. The end result is a scheme that only permits executions which are guaranteed to preserve the atomicity properties derived from the profile. Evaluation results on large, realworld, open-source programs show that our technique can effectively suppress subtle concurrency bugs, with small runtime overheads (typically less than 15%)

    Analyzing multicore dumps to facilitate concurrency bug reproduction

    No full text
    Debugging concurrent programs is difficult. This is primarily because the inherent non-determinism that arises because of scheduler interleavings makes it hard to easily reproduce bugs that may manifest only under certain interleavings. The problem is exacerbated in multi-core environments where there are multiple schedulers, one for each core. In this paper, we propose a reproduction technique for concurrent programs that execute on multi-core platforms. Our technique performs a lightweight analysis of a failing execution that occurs in a multi-core environment, and uses the result of the analysis to enable reproduction of the bug in a singlecore system, under the control of a deterministic scheduler. More specifically, our approach automatically identifies the execution point in the re-execution that corresponds to the failure point. It does so by analyzing the failure core dump and leveraging a technique called execution indexing that identifies a related point in the re-execution. By generating a core dump at this point, and comparing the differences betwen the two dumps, we are able to guide a search algorithm to efficiently generate a failure inducing schedule. Our experiments show that our technique is highly effective and has reasonable overhead

    Precise Calling Context Encoding

    No full text
    Calling contexts are very important for a wide range of applications such as profiling, debugging, and event logging. Most applications perform expensive stack walking to recover contexts. The resulting contexts are often explicitly represented as a sequence of call sites and hence bulky. We propose a technique to encode the current calling context of any point during an execution. In particular, an acyclic call path is encoded into one number through only integer additions. Recursive call paths are divided into acyclic subsequences and encoded independently. We leverage stack depth in a safe way to optimize encoding: if a calling context can be safely and uniquely identified by its stack depth, we do not perform encoding. We propose an algorithm to seamlessly fuse encoding and stack depth based identification. The algorithm is safe because different contexts are guaranteed to have different IDs. It also ensures contexts can be faithfully decoded. Our experiments show that our technique incurs negligible overhead (1.89 % on average). For most medium-sized programs, it can encode all contexts with just one number. For large programs, we are able to encode most calling contexts to a few numbers. 1

    Accentuating the positive

    No full text
    corecore